diff -ur webform.orig/components/select.inc modules/webform/components/select.inc --- webform.orig/components/select.inc 2009-05-12 13:53:01.000000000 -0400 +++ modules/webform/components/select.inc 2009-05-12 14:06:23.000000000 -0400 @@ -104,7 +104,14 @@ // Convert the user-entered options list into an array. $default_value = _webform_filter_values($component['value'], NULL, NULL, FALSE); - $options = _webform_select_options($component['extra']['items'], $component['extra']['aslist'] != 'Y'); + + // If email is enabled, hash the email addresses + if ($component['extra']['email']) { + $options = _webform_select_options($component['extra']['items'], $component['extra']['aslist'] !== 'Y', TRUE); + } + else { + $options = _webform_select_options($component['extra']['items'], $component['extra']['aslist'] !== 'Y', FALSE); + } if ($component['extra']['aslist'] == 'Y' && $component['extra']['multiple'] != 'Y') { $options = array('' => t('select...')) + $options; @@ -214,7 +221,13 @@ * Nothing. */ function _webform_submit_select(&$data, $component) { - $options = drupal_map_assoc(array_flip(_webform_select_options($component['extra']['items'], TRUE))); + // If email is enabled, hash the email addresses + if ($component['extra']['email']) { + $options = drupal_map_assoc(array_flip(_webform_select_options($component['extra']['items'], TRUE, TRUE))); + } + else { + $options = drupal_map_assoc(array_flip(_webform_select_options($component['extra']['items'], TRUE))); + } if (is_array($data)) { foreach ($data as $key => $value) { @@ -244,8 +257,14 @@ * Textual output to be included in the email. */ function theme_webform_mail_select($data, $component) { - // Convert submitted 'safe' values to un-edited, original form. - $options = _webform_select_options($component['extra']['items']); + // Convert submitted 'safe' values to un-edited, original form. Hash if email + // is enabled. + if ($component['extra']['email']) { + $options = _webform_select_options($component['extra']['items'], TRUE, TRUE); + } + else { + $options = _webform_select_options($component['extra']['items'], TRUE, FALSE); + } // Generate the output. if ($component['extra']['multiple']) { @@ -427,9 +446,10 @@ * @param $flat * Optional. If specified, return the option array and exclude any optgroups. */ -function _webform_select_options($text, $flat = FALSE) { +function _webform_select_options($text, $flat = FALSE, $hash_emails = FALSE) { $options = array(); $rows = array_filter(explode("\n", trim($text))); + $count = 0; $group = NULL; foreach ($rows as $option) { $option = trim($option); @@ -454,7 +474,20 @@ else if (preg_match('/^([^|]+)\|(.*)$/', $option, $matches)) { $key = _webform_filter_values($matches[1], NULL, NULL, FALSE); $value = _webform_filter_values($matches[2], NULL, NULL, FALSE); - isset($group) ? $options[$group][$key] = $value : $options[$key] = $value; + + if ($hash_emails) { + if (valid_email_address($matches[1])) { + $hash = _webform_hash_email($matches[1]); + if ((isset($group) && isset($options[$group][$hash])) || isset($options[$hash])) { + $hash .= '-' . $count; + $count ++; + } + isset($group) ? $options[$group][$hash] = $value : $options[$hash] = $value; + } + } + else { + isset($group) ? $options[$group][$key] = $value : $options[$key] = $value; + } } else { $filtered_option = _webform_filter_values($option, NULL, NULL, FALSE); @@ -463,3 +496,44 @@ } return $options; } + +/** + * Given an email address, return it's md5 hash, either from the database or + * by calculating and storing it. + * + * @param $email + * The email address to hash. + * @return + * The md5 hash of the email. + */ +function _webform_hash_email($email) { + $query = "SELECT hash FROM {webform_email_hashes} WHERE email = '%s'"; + $hash = db_result(db_query($query, $email)); + + if (empty($hash)) { + $hash = md5($email); + $query = "INSERT INTO {webform_email_hashes} (hash, email) VALUES('%s', '%s')"; + db_query($query, $hash, $email); + } + + return $hash; +} + +/** + * Given an md5 hash, return the email associated with it as stored in the + * database. + * + * @param $hash + * A 32-character long md5 hash. + * + * @return + * The associated email address, or NULL if no address was found. + */ +function _webform_get_hash_email($hash) { + if (strlen($hash) > 32) { + $hash = substr($hash, 0, 32); + } + $query = "SELECT email FROM {webform_email_hashes} WHERE hash = '%s'"; + return db_result(db_query($query, $hash)); +} + Only in modules/webform/components: select.inc.orig Only in modules/webform/components: select.inc.rej Only in modules/webform/: webform_email_hash_patch.txt diff -ur webform.orig/webform.install modules/webform/webform.install --- webform.orig/webform.install 2009-05-12 13:53:01.000000000 -0400 +++ modules/webform/webform.install 2009-05-14 14:44:11.000000000 -0400 @@ -273,6 +273,25 @@ 'primary key' => array('nid', 'sid', 'cid', 'no'), ); + $schema['webform_email_hashes'] = array( + 'description' => t('Holds hashes for email addresses entered into select fields.'), + 'fields' => array( + 'hash' => array( + 'description' => t('The hash of the email address.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), + 'email' => array( + 'description' => t('The original email address.'), + 'type' => 'varchar', + 'length' => EMAIL_MAX_LENGTH, + 'not null' => TRUE, + ), + ), + 'primary key' => array('hash', 'email'), + ); + return $schema; } @@ -892,6 +911,38 @@ } /** + * Per-webform submission access control based on roles. + */ +function webform_update_6205() { + $ret = array(); + + if (db_table_exists('webform_email_hashes')) { + return $ret; + } + + db_create_table($ret, 'webform_email_hashes', array( + 'description' => t('Holds hashes for email addresses entered into select fields.'), + 'fields' => array( + 'hash' => array( + 'description' => t('The hash of the email address.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), + 'email' => array( + 'description' => t('The original email address.'), + 'type' => 'varchar', + 'length' => EMAIL_MAX_LENGTH, + 'not null' => TRUE, + ), + ), + 'primary key' => array('hash', 'email'), + )); + + return $ret; +} + +/** * Cleanup filtering values used by the file component. * * Previously, file extensions were saved by category, exactly as the FormAPI @@ -953,6 +1004,35 @@ return $ret; } + /** + * Add a table to store email addresses and their unique hash mappings. This + * allows emails to be hidden to the client and for multiple select options to + * point to a single email address. + */ +function webform_update_5204() { + $ret = array(); + switch ($GLOBALS['db_type']) { + case 'mysqli': + case 'mysql': + $ret[] = update_sql("CREATE TABLE {webform_email_hashes} ( + hash char(32) NOT NULL, + email varchar(" . EMAIL_MAX_LENGTH . ") NOT NULL, + PRIMARY KEY (hash, email) + ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */" + ); + break; + case 'pgsql': + $ret[] = update_sql("CREATE TABLE {webform_email_hashes} ( + hash char(32) NOT NULL, + email varchar(" . EMAIL_MAX_LENGTH . ") NOT NULL, + PRIMARY KEY (hash, email) + )" + ); + break; + } + return $ret; +} + /** * Recursively delete all files and folders in the specified filepath, then * delete the containing folder. Only in modules/webform/: webform.install.orig Only in modules/webform/: webform.install.rej diff -ur webform.orig/webform.module modules/webform/webform.module --- webform.orig/webform.module 2009-05-12 13:53:01.000000000 -0400 +++ modules/webform/webform.module 2009-05-14 15:11:26.000000000 -0400 @@ -1656,17 +1656,29 @@ $form_state['values']['submitted'] = _webform_client_form_submit_flatten($node, $form_state['values']['submitted']); // Convert additional email addresses into actual values. - foreach ($node->webform['additional_emails'] as $cid => $value) { + foreach ($form_state['values']['submitted'] as $cid => $value) { if (is_array($form_state['values']['submitted'][$cid])) { $node->webform['additional_emails'][$cid] = array(); foreach ($form_state['values']['submitted'][$cid] as $submitted_value) { if ($submitted_value) { - $node->webform['additional_emails'][$cid][] = $submitted_value; + // If we find that the value has been hashed, convert it to an email + // address. + if (strlen($submitted_value) >= 32 && !valid_email_address($submitted_value) && ($email = _webform_get_hash_email($submitted_value))) { + $node->webform['additional_emails'][$cid][] = $email; + } + else { + $node->webform['additional_emails'][$cid][] = $submitted_value; + } } } } else { - $node->webform['additional_emails'][$cid] = $form_state['values']['submitted'][$cid]; + if (strlen($form_state['values']['submitted'][$cid]) >= 32 && !valid_email_address($form_state['values']['submitted'][$cid]) && ($email = _webform_get_hash_email($form_state['values']['submitted'][$cid]))) { + $node->webform['additional_emails'][$cid] = $email; + } + else { + $node->webform['additional_emails'][$cid] = $form_state['values']['submitted'][$cid]; + } } if (empty($node->webform['additional_emails'][$cid])) { unset($node->webform['additional_emails'][$cid]); Only in modules/webform/: webform.module.orig Only in modules/webform/: webform.module.rej